home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / perl / msds-prl / prl386l1.zoo / doio.c < prev    next >
C/C++ Source or Header  |  1992-07-29  |  67KB  |  2,960 lines

  1. static char *rcsid = "$Id: DOIO.C 1.1 92/07/19 14:25:43 doi Exp $";
  2. /* RCSfile: doio.c,v Revision: 4.0.1.6 Date: 92/06/11 21:08:16 
  3.  *
  4.  *    Copyright (c) 1991, Larry Wall
  5.  *
  6.  *    You may distribute under the terms of either the GNU General Public
  7.  *    License or the Artistic License, as specified in the README file.
  8.  *
  9.  * Log:    doio.c,v 
  10.  * Revision 4.0.1.6  92/06/11  21:08:16  lwall
  11.  * patch34: some systems don't declare h_errno extern in header files
  12.  * 
  13.  * Revision 4.0.1.5  92/06/08  13:00:21  lwall
  14.  * patch20: some machines don't define ENOTSOCK in errno.h
  15.  * patch20: new warnings for failed use of stat operators on filenames with \n
  16.  * patch20: wait failed when STDOUT or STDERR reopened to a pipe
  17.  * patch20: end of file latch not reset on reopen of STDIN
  18.  * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
  19.  * patch20: fixed memory leak on system() for vfork() machines
  20.  * patch20: get*by* routines now return something useful in a scalar context
  21.  * patch20: h_errno now accessible via $?
  22.  * 
  23.  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
  24.  * patch11: prepared for ctype implementations that don't define isascii()
  25.  * patch11: perl mistook some streams for sockets because they return mode 0 too
  26.  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
  27.  * patch11: certain perl errors should set EBADF so that $! looks better
  28.  * patch11: truncate on a closed filehandle could dump
  29.  * patch11: stats of _ forgot whether prior stat was actually lstat
  30.  * patch11: -T returned true on NFS directory
  31.  * 
  32.  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
  33.  * patch10: read didn't work from character special files open for writing
  34.  * patch10: close-on-exec wrongly set on system file descriptors
  35.  * 
  36.  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
  37.  * patch4: new copyright notice
  38.  * patch4: system fd's are now treated specially
  39.  * patch4: added $^F variable to specify maximum system fd, default 2
  40.  * patch4: character special files now opened with bidirectional stdio buffers
  41.  * patch4: taintchecks could improperly modify parent in vfork()
  42.  * patch4: many, many itty-bitty portability fixes
  43.  * 
  44.  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
  45.  * patch1: hopefully straightened out some of the Xenix mess
  46.  * 
  47.  * Revision 4.0  91/03/20  01:07:06  lwall
  48.  * 4.0 baseline.
  49.  * 
  50.  */
  51.  
  52. #include "EXTERN.h"
  53. #include "perl.h"
  54.  
  55. #ifdef HAS_SOCKET
  56. #include <sys/socket.h>
  57. #include <netdb.h>
  58. #ifndef ENOTSOCK
  59. #include <net/errno.h>
  60. #endif
  61. #endif
  62.  
  63. #ifdef HAS_SELECT
  64. #ifdef I_SYS_SELECT
  65. #ifndef I_SYS_TIME
  66. #include <sys/select.h>
  67. #endif
  68. #endif
  69. #endif
  70.  
  71. #ifdef HOST_NOT_FOUND
  72. extern int h_errno;
  73. #endif
  74.  
  75. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  76. #include <sys/ipc.h>
  77. #ifdef HAS_MSG
  78. #include <sys/msg.h>
  79. #endif
  80. #ifdef HAS_SEM
  81. #include <sys/sem.h>
  82. #endif
  83. #ifdef HAS_SHM
  84. #include <sys/shm.h>
  85. #endif
  86. #endif
  87.  
  88. #ifdef I_PWD
  89. #include <pwd.h>
  90. #endif
  91. #ifdef I_GRP
  92. #include <grp.h>
  93. #endif
  94. #ifdef I_UTIME
  95. #include <utime.h>
  96. #endif
  97. #ifdef I_FCNTL
  98. #include <fcntl.h>
  99. #endif
  100. #ifdef I_SYS_FILE
  101. #include <sys/file.h>
  102. #endif
  103.  
  104. int laststatval = -1;
  105. int laststype = O_STAT;
  106.  
  107. static char* warn_nl = "Unsuccessful %s on filename containing newline";
  108.  
  109. bool
  110. do_open(stab,name,len)
  111. STAB *stab;
  112. register char *name;
  113. int len;
  114. {
  115.     FILE *fp;
  116.     register STIO *stio = stab_io(stab);
  117.     char *myname = savestr(name);
  118.     int result;
  119.     int fd;
  120.     int writing = 0;
  121.     char mode[3];        /* stdio file mode ("r\0" or "r+\0") */
  122.     FILE *saveifp = Nullfp;
  123.     FILE *saveofp = Nullfp;
  124.     char savetype = ' ';
  125.  
  126.     mode[0] = mode[1] = mode[2] = '\0';
  127.     name = myname;
  128.     forkprocess = 1;        /* assume true if no fork */
  129.     while (len && isSPACE(name[len-1]))
  130.     name[--len] = '\0';
  131.     if (!stio)
  132.     stio = stab_io(stab) = stio_new();
  133.     else if (stio->ifp) {
  134.     fd = fileno(stio->ifp);
  135.     if (stio->type == '-')
  136.         result = 0;
  137.     else if (fd <= maxsysfd) {
  138.         saveifp = stio->ifp;
  139.         saveofp = stio->ofp;
  140.         savetype = stio->type;
  141.         result = 0;
  142.     }
  143.     else if (stio->type == '|')
  144.         result = mypclose(stio->ifp);
  145.     else if (stio->ifp != stio->ofp) {
  146.         if (stio->ofp) {
  147.         result = fclose(stio->ofp);
  148.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  149.         }
  150.         else
  151.         result = fclose(stio->ifp);
  152.     }
  153.     else
  154.         result = fclose(stio->ifp);
  155.     if (result == EOF && fd > maxsysfd)
  156.         fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  157.           stab_ename(stab));
  158.     stio->ofp = stio->ifp = Nullfp;
  159.     }
  160.     if (*name == '+' && len > 1 && name[len-1] != '|') {    /* scary */
  161.     mode[1] = *name++;
  162.     mode[2] = '\0';
  163.     --len;
  164.     writing = 1;
  165.     }
  166.     else  {
  167.     mode[1] = '\0';
  168.     }
  169.     stio->type = *name;
  170.     if (*name == '|') {
  171.     /*SUPPRESS 530*/
  172.     for (name++; isSPACE(*name); name++) ;
  173. #ifdef TAINT
  174.     taintenv();
  175.     taintproper("Insecure dependency in piped open");
  176. #endif
  177.     fp = mypopen(name,"w");
  178.     writing = 1;
  179.     }
  180.     else if (*name == '>') {
  181. #ifdef TAINT
  182.     taintproper("Insecure dependency in open");
  183. #endif
  184.     name++;
  185.     if (*name == '>') {
  186.         mode[0] = stio->type = 'a';
  187.         name++;
  188.     }
  189.     else
  190.         mode[0] = 'w';
  191.     writing = 1;
  192.     if (*name == '&') {
  193.       duplicity:
  194.         name++;
  195.         while (isSPACE(*name))
  196.         name++;
  197.         if (isDIGIT(*name))
  198.         fd = atoi(name);
  199.         else {
  200.         stab = stabent(name,FALSE);
  201.         if (!stab || !stab_io(stab)) {
  202. #ifdef EINVAL
  203.             errno = EINVAL;
  204. #endif
  205.             goto say_false;
  206.         }
  207.         if (stab_io(stab) && stab_io(stab)->ifp) {
  208.             fd = fileno(stab_io(stab)->ifp);
  209.             if (stab_io(stab)->type == 's')
  210.             stio->type = 's';
  211.         }
  212.         else
  213.             fd = -1;
  214.         }
  215.         if (!(fp = fdopen(fd = dup(fd),mode))) {
  216.         close(fd);
  217.         }
  218.     }
  219.     else {
  220.         while (isSPACE(*name))
  221.         name++;
  222.         if (strEQ(name,"-")) {
  223.         fp = stdout;
  224.         stio->type = '-';
  225.         }
  226.         else  {
  227.         fp = fopen(name,mode);
  228.         }
  229.     }
  230.     }
  231.     else {
  232.     if (*name == '<') {
  233.         mode[0] = 'r';
  234.         name++;
  235.         while (isSPACE(*name))
  236.         name++;
  237.         if (*name == '&')
  238.         goto duplicity;
  239.         if (strEQ(name,"-")) {
  240.         fp = stdin;
  241.         stio->type = '-';
  242.         }
  243.         else
  244.         fp = fopen(name,mode);
  245.     }
  246.     else if (name[len-1] == '|') {
  247. #ifdef TAINT
  248.         taintenv();
  249.         taintproper("Insecure dependency in piped open");
  250. #endif
  251.         name[--len] = '\0';
  252.         while (len && isSPACE(name[len-1]))
  253.         name[--len] = '\0';
  254.         /*SUPPRESS 530*/
  255.         for (; isSPACE(*name); name++) ;
  256.         fp = mypopen(name,"r");
  257.         stio->type = '|';
  258.     }
  259.     else {
  260.         stio->type = '<';
  261.         /*SUPPRESS 530*/
  262.         for (; isSPACE(*name); name++) ;
  263.         if (strEQ(name,"-")) {
  264.         fp = stdin;
  265.         stio->type = '-';
  266.         }
  267.         else
  268.         fp = fopen(name,"r");
  269.     }
  270.     }
  271.     if (!fp) {
  272.     if (dowarn && stio->type == '<' && index(name, '\n'))
  273.         warn(warn_nl, "open");
  274.     Safefree(myname);
  275.     goto say_false;
  276.     }
  277.     Safefree(myname);
  278.     if (stio->type &&
  279.       stio->type != '|' && stio->type != '-') {
  280.     if (fstat(fileno(fp),&statbuf) < 0) {
  281.         (void)fclose(fp);
  282.         goto say_false;
  283.     }
  284.     if (S_ISSOCK(statbuf.st_mode))
  285.         stio->type = 's';    /* in case a socket was passed in to us */
  286. #ifdef HAS_SOCKET
  287.     else if (
  288. #ifdef S_IFMT
  289.         !(statbuf.st_mode & S_IFMT)
  290. #else
  291.         !statbuf.st_mode
  292. #endif
  293.     ) {
  294.         int buflen = sizeof tokenbuf;
  295.         if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
  296.         || errno != ENOTSOCK)
  297.         stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
  298.                 /* but some return 0 for streams too, sigh */
  299.     }
  300. #endif
  301.     }
  302.     if (saveifp) {        /* must use old fp? */
  303.     fd = fileno(saveifp);
  304.     if (saveofp) {
  305.         fflush(saveofp);        /* emulate fclose() */
  306.         if (saveofp != saveifp) {    /* was a socket? */
  307.         fclose(saveofp);
  308.         if (fd > 2)
  309.             Safefree(saveofp);
  310.         }
  311.     }
  312.     if (fd != fileno(fp)) {
  313.         int pid;
  314.         STR *str;
  315.  
  316.         dup2(fileno(fp), fd);
  317.         str = afetch(fdpid,fileno(fp),TRUE);
  318.         pid = str->str_u.str_useful;
  319.         str->str_u.str_useful = 0;
  320.         str = afetch(fdpid,fd,TRUE);
  321.         str->str_u.str_useful = pid;
  322.         fclose(fp);
  323.  
  324.     }
  325.     fp = saveifp;
  326.     clearerr(fp);
  327.     }
  328. #if defined(HAS_FCNTL) && defined(F_SETFD)
  329.     fd = fileno(fp);
  330.     fcntl(fd,F_SETFD,fd > maxsysfd);
  331. #endif
  332.     stio->ifp = fp;
  333.     if (writing) {
  334.     if (stio->type == 's'
  335.       || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
  336.         if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
  337.         fclose(fp);
  338.         stio->ifp = Nullfp;
  339.         goto say_false;
  340.         }
  341.     }
  342.     else
  343.         stio->ofp = fp;
  344.     }
  345.     return TRUE;
  346.  
  347. say_false:
  348.     stio->ifp = saveifp;
  349.     stio->ofp = saveofp;
  350.     stio->type = savetype;
  351.     return FALSE;
  352. }
  353.  
  354. FILE *
  355. nextargv(stab)
  356. register STAB *stab;
  357. {
  358.     register STR *str;
  359. #ifndef FLEXFILENAMES
  360.     int filedev;
  361.     int fileino;
  362. #endif
  363.     int fileuid;
  364.     int filegid;
  365.     static int filemode = 0;
  366.     static int lastfd;
  367.     static char *oldname;
  368.  
  369.     if (!argvoutstab)
  370.     argvoutstab = stabent("ARGVOUT",TRUE);
  371.     if (filemode & (S_ISUID|S_ISGID)) {
  372.     fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
  373. #ifdef HAS_FCHMOD
  374.     (void)fchmod(lastfd,filemode);
  375. #else
  376.     (void)chmod(oldname,filemode);
  377. #endif
  378.     }
  379.     filemode = 0;
  380.     while (alen(stab_xarray(stab)) >= 0) {
  381.     str = ashift(stab_xarray(stab));
  382.     str_sset(stab_val(stab),str);
  383.     STABSET(stab_val(stab));
  384.     oldname = str_get(stab_val(stab));
  385.     if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
  386.         if (inplace) {
  387. #ifdef TAINT
  388.         taintproper("Insecure dependency in inplace open");
  389. #endif
  390.         if (strEQ(oldname,"-")) {
  391.             str_free(str);
  392.             defoutstab = stabent("STDOUT",TRUE);
  393.             return stab_io(stab)->ifp;
  394.         }
  395. #ifndef FLEXFILENAMES
  396.         filedev = statbuf.st_dev;
  397.         fileino = statbuf.st_ino;
  398. #endif
  399.         filemode = statbuf.st_mode;
  400.         fileuid = statbuf.st_uid;
  401.         filegid = statbuf.st_gid;
  402.         if (!S_ISREG(filemode)) {
  403.             warn("Can't do inplace edit: %s is not a regular file",
  404.               oldname );
  405.             do_close(stab,FALSE);
  406.             str_free(str);
  407.             continue;
  408.         }
  409.         if (*inplace) {
  410. #ifdef SUFFIX
  411.             add_suffix(str,inplace);
  412. #else
  413.             str_cat(str,inplace);
  414. #endif
  415. #ifndef FLEXFILENAMES
  416.             if (stat(str->str_ptr,&statbuf) >= 0
  417.               && statbuf.st_dev == filedev
  418.               && statbuf.st_ino == fileino ) {
  419.             warn("Can't do inplace edit: %s > 14 characters",
  420.               str->str_ptr );
  421.             do_close(stab,FALSE);
  422.             str_free(str);
  423.             continue;
  424.             }
  425. #endif
  426. #ifdef HAS_RENAME
  427. #ifndef DOSISH
  428.             if (rename(oldname,str->str_ptr) < 0) {
  429.             warn("Can't rename %s to %s: %s, skipping file",
  430.               oldname, str->str_ptr, strerror(errno) );
  431.             do_close(stab,FALSE);
  432.             str_free(str);
  433.             continue;
  434.             }
  435. #else
  436.             do_close(stab,FALSE);
  437.             (void)unlink(str->str_ptr);
  438.             (void)rename(oldname,str->str_ptr);
  439.             do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
  440. #endif /* MSDOS */
  441. #else
  442.             (void)UNLINK(str->str_ptr);
  443.             if (link(oldname,str->str_ptr) < 0) {
  444.             warn("Can't rename %s to %s: %s, skipping file",
  445.               oldname, str->str_ptr, strerror(errno) );
  446.             do_close(stab,FALSE);
  447.             str_free(str);
  448.             continue;
  449.             }
  450.             (void)UNLINK(oldname);
  451. #endif
  452.         }
  453.         else {
  454. #ifndef DOSISH
  455.             if (UNLINK(oldname) < 0) {
  456.             warn("Can't rename %s to %s: %s, skipping file",
  457.               oldname, str->str_ptr, strerror(errno) );
  458.             do_close(stab,FALSE);
  459.             str_free(str);
  460.             continue;
  461.             }
  462. #else
  463.             fatal("Can't do inplace edit without backup");
  464. #endif
  465.         }
  466.  
  467.         str_nset(str,">",1);
  468.         str_cat(str,oldname);
  469.         errno = 0;        /* in case sprintf set errno */
  470.         if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
  471.             warn("Can't do inplace edit on %s: %s",
  472.               oldname, strerror(errno) );
  473.             do_close(stab,FALSE);
  474.             str_free(str);
  475.             continue;
  476.         }
  477.         defoutstab = argvoutstab;
  478.         lastfd = fileno(stab_io(argvoutstab)->ifp);
  479.         (void)fstat(lastfd,&statbuf);
  480. #ifdef HAS_FCHMOD
  481.         (void)fchmod(lastfd,filemode);
  482. #else
  483.         (void)chmod(oldname,filemode);
  484. #endif
  485.         if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
  486. #ifdef HAS_FCHOWN
  487.             (void)fchown(lastfd,fileuid,filegid);
  488. #else
  489. #ifdef HAS_CHOWN
  490.             (void)chown(oldname,fileuid,filegid);
  491. #endif
  492. #endif
  493.         }
  494.         }
  495.         str_free(str);
  496.         return stab_io(stab)->ifp;
  497.     }
  498.     else
  499.         fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
  500.     str_free(str);
  501.     }
  502.     if (inplace) {
  503.     (void)do_close(argvoutstab,FALSE);
  504.     defoutstab = stabent("STDOUT",TRUE);
  505.     }
  506.     return Nullfp;
  507. }
  508.  
  509. #ifdef HAS_PIPE
  510. void
  511. do_pipe(str, rstab, wstab)
  512. STR *str;
  513. STAB *rstab;
  514. STAB *wstab;
  515. {
  516.     register STIO *rstio;
  517.     register STIO *wstio;
  518.     int fd[2];
  519.  
  520.     if (!rstab)
  521.     goto badexit;
  522.     if (!wstab)
  523.     goto badexit;
  524.  
  525.     rstio = stab_io(rstab);
  526.     wstio = stab_io(wstab);
  527.  
  528.     if (!rstio)
  529.     rstio = stab_io(rstab) = stio_new();
  530.     else if (rstio->ifp)
  531.     do_close(rstab,FALSE);
  532.     if (!wstio)
  533.     wstio = stab_io(wstab) = stio_new();
  534.     else if (wstio->ifp)
  535.     do_close(wstab,FALSE);
  536.  
  537.     if (pipe(fd) < 0)
  538.     goto badexit;
  539.     rstio->ifp = fdopen(fd[0], "r");
  540.     wstio->ofp = fdopen(fd[1], "w");
  541.     wstio->ifp = wstio->ofp;
  542.     rstio->type = '<';
  543.     wstio->type = '>';
  544.     if (!rstio->ifp || !wstio->ofp) {
  545.     if (rstio->ifp) fclose(rstio->ifp);
  546.     else close(fd[0]);
  547.     if (wstio->ofp) fclose(wstio->ofp);
  548.     else close(fd[1]);
  549.     goto badexit;
  550.     }
  551.  
  552.     str_sset(str,&str_yes);
  553.     return;
  554.  
  555. badexit:
  556.     str_sset(str,&str_undef);
  557.     return;
  558. }
  559. #endif
  560.  
  561. bool
  562. do_close(stab,explicit)
  563. STAB *stab;
  564. bool explicit;
  565. {
  566.     bool retval = FALSE;
  567.     register STIO *stio;
  568.     int status;
  569.  
  570.     if (!stab)
  571.     stab = argvstab;
  572.     if (!stab) {
  573.     errno = EBADF;
  574.     return FALSE;
  575.     }
  576.     stio = stab_io(stab);
  577.     if (!stio) {        /* never opened */
  578.     if (dowarn && explicit)
  579.         warn("Close on unopened file <%s>",stab_ename(stab));
  580.     return FALSE;
  581.     }
  582.     if (stio->ifp) {
  583.     if (stio->type == '|') {
  584.         status = mypclose(stio->ifp);
  585.         retval = (status == 0);
  586.         statusvalue = (unsigned short)status & 0xffff;
  587.     }
  588.     else if (stio->type == '-')
  589.         retval = TRUE;
  590.     else {
  591.         if (stio->ofp && stio->ofp != stio->ifp) {        /* a socket */
  592.         retval = (fclose(stio->ofp) != EOF);
  593.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  594.         }
  595.         else
  596.         retval = (fclose(stio->ifp) != EOF);
  597.     }
  598.     stio->ofp = stio->ifp = Nullfp;
  599.     }
  600.     if (explicit)
  601.     stio->lines = 0;
  602.     stio->type = ' ';
  603.     return retval;
  604. }
  605.  
  606. bool
  607. do_eof(stab)
  608. STAB *stab;
  609. {
  610.     register STIO *stio;
  611.     int ch;
  612.  
  613.     if (!stab) {            /* eof() */
  614.     if (argvstab)
  615.         stio = stab_io(argvstab);
  616.     else
  617.         return TRUE;
  618.     }
  619.     else
  620.     stio = stab_io(stab);
  621.  
  622.     if (!stio)
  623.     return TRUE;
  624.  
  625.     while (stio->ifp) {
  626.  
  627. #ifdef STDSTDIO            /* (the code works without this) */
  628.     if (stio->ifp->_cnt > 0)    /* cheat a little, since */
  629.         return FALSE;        /* this is the most usual case */
  630. #endif
  631.  
  632.     ch = getc(stio->ifp);
  633.     if (ch != EOF) {
  634.         (void)ungetc(ch, stio->ifp);
  635.         return FALSE;
  636.     }
  637. #ifdef STDSTDIO
  638.     if (stio->ifp->_cnt < -1)
  639.         stio->ifp->_cnt = -1;
  640. #endif
  641.     if (!stab) {            /* not necessarily a real EOF yet? */
  642.         if (!nextargv(argvstab))    /* get another fp handy */
  643.         return TRUE;
  644.     }
  645.     else
  646.         return TRUE;        /* normal fp, definitely end of file */
  647.     }
  648.     return TRUE;
  649. }
  650.  
  651. long
  652. do_tell(stab)
  653. STAB *stab;
  654. {
  655.     register STIO *stio;
  656.  
  657.     if (!stab)
  658.     goto phooey;
  659.  
  660.     stio = stab_io(stab);
  661.     if (!stio || !stio->ifp)
  662.     goto phooey;
  663.  
  664. #ifdef ULTRIX_STDIO_BOTCH
  665.     if (feof(stio->ifp))
  666.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  667. #endif
  668.  
  669.     return ftell(stio->ifp);
  670.  
  671. phooey:
  672.     if (dowarn)
  673.     warn("tell() on unopened file");
  674.     errno = EBADF;
  675.     return -1L;
  676. }
  677.  
  678. bool
  679. do_seek(stab, pos, whence)
  680. STAB *stab;
  681. long pos;
  682. int whence;
  683. {
  684.     register STIO *stio;
  685.  
  686.     if (!stab)
  687.     goto nuts;
  688.  
  689.     stio = stab_io(stab);
  690.     if (!stio || !stio->ifp)
  691.     goto nuts;
  692.  
  693. #ifdef ULTRIX_STDIO_BOTCH
  694.     if (feof(stio->ifp))
  695.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  696. #endif
  697.  
  698.     return fseek(stio->ifp, pos, whence) >= 0;
  699.  
  700. nuts:
  701.     if (dowarn)
  702.     warn("seek() on unopened file");
  703.     errno = EBADF;
  704.     return FALSE;
  705. }
  706.  
  707. int
  708. do_ctl(optype,stab,func,argstr)
  709. int optype;
  710. STAB *stab;
  711. int func;
  712. STR *argstr;
  713. {
  714.     register STIO *stio;
  715.     register char *s;
  716.     int retval;
  717.  
  718.     if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
  719.     errno = EBADF;    /* well, sort of... */
  720.     return -1;
  721.     }
  722.  
  723.     if (argstr->str_pok || !argstr->str_nok) {
  724.     if (!argstr->str_pok)
  725.         s = str_get(argstr);
  726.  
  727. #ifdef IOCPARM_MASK
  728. #ifndef IOCPARM_LEN
  729. #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
  730. #endif
  731. #endif
  732. #ifdef IOCPARM_LEN
  733.     retval = IOCPARM_LEN(func);    /* on BSDish systes we're safe */
  734. #else
  735.     retval = 256;            /* otherwise guess at what's safe */
  736. #endif
  737.     if (argstr->str_cur < retval) {
  738.         Str_Grow(argstr,retval+1);
  739.         argstr->str_cur = retval;
  740.     }
  741.  
  742.     s = argstr->str_ptr;
  743.     s[argstr->str_cur] = 17;    /* a little sanity check here */
  744.     }
  745.     else {
  746.     retval = (int)str_gnum(argstr);
  747. #ifdef DOSISH
  748.     s = (char*)(long)retval;        /* ouch */
  749. #else
  750.     s = (char*)retval;        /* ouch */
  751. #endif
  752.     }
  753.  
  754. #ifndef lint
  755.     if (optype == O_IOCTL)
  756.     retval = ioctl(fileno(stio->ifp), func, s);
  757.     else
  758. #ifdef DOSISH
  759.     fatal("fcntl is not implemented");
  760. #else
  761. #ifdef HAS_FCNTL
  762.     retval = fcntl(fileno(stio->ifp), func, s);
  763. #else
  764.     fatal("fcntl is not implemented");
  765. #endif
  766. #endif
  767. #else /* lint */
  768.     retval = 0;
  769. #endif /* lint */
  770.  
  771.     if (argstr->str_pok) {
  772.     if (s[argstr->str_cur] != 17)
  773.         fatal("Return value overflowed string");
  774.     s[argstr->str_cur] = 0;        /* put our null back */
  775.     }
  776.     return retval;
  777. }
  778.  
  779. int
  780. do_stat(str,arg,gimme,arglast)
  781. STR *str;
  782. register ARG *arg;
  783. int gimme;
  784. int *arglast;
  785. {
  786.     register ARRAY *ary = stack;
  787.     register int sp = arglast[0] + 1;
  788.     int max = 13;
  789.  
  790.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  791.     tmpstab = arg[1].arg_ptr.arg_stab;
  792.     if (tmpstab != defstab) {
  793.         laststype = O_STAT;
  794.         statstab = tmpstab;
  795.         str_set(statname,"");
  796.         if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  797.           fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
  798.         max = 0;
  799.         laststatval = -1;
  800.         }
  801.     }
  802.     else if (laststatval < 0)
  803.         max = 0;
  804.     }
  805.     else {
  806.     str_set(statname,str_get(ary->ary_array[sp]));
  807.     statstab = Nullstab;
  808. #ifdef HAS_LSTAT
  809.     laststype = arg->arg_type;
  810.     if (arg->arg_type == O_LSTAT)
  811.         laststatval = lstat(str_get(statname),&statcache);
  812.     else
  813. #endif
  814.         laststatval = stat(str_get(statname),&statcache);
  815.     if (laststatval < 0) {
  816.         if (dowarn && index(str_get(statname), '\n'))
  817.         warn(warn_nl, "stat");
  818.         max = 0;
  819.     }
  820.     }
  821.  
  822.     if (gimme != G_ARRAY) {
  823.     if (max)
  824.         str_sset(str,&str_yes);
  825.     else
  826.         str_sset(str,&str_undef);
  827.     STABSET(str);
  828.     ary->ary_array[sp] = str;
  829.     return sp;
  830.     }
  831.     sp--;
  832.     if (max) {
  833. #ifndef lint
  834.     (void)astore(ary,++sp,
  835.       str_2mortal(str_nmake((double)statcache.st_dev)));
  836.     (void)astore(ary,++sp,
  837.       str_2mortal(str_nmake((double)statcache.st_ino)));
  838.     (void)astore(ary,++sp,
  839.       str_2mortal(str_nmake((double)statcache.st_mode)));
  840.     (void)astore(ary,++sp,
  841.       str_2mortal(str_nmake((double)statcache.st_nlink)));
  842.     (void)astore(ary,++sp,
  843.       str_2mortal(str_nmake((double)statcache.st_uid)));
  844.     (void)astore(ary,++sp,
  845.       str_2mortal(str_nmake((double)statcache.st_gid)));
  846.     (void)astore(ary,++sp,
  847.       str_2mortal(str_nmake((double)statcache.st_rdev)));
  848.     (void)astore(ary,++sp,
  849.       str_2mortal(str_nmake((double)statcache.st_size)));
  850.     (void)astore(ary,++sp,
  851.       str_2mortal(str_nmake((double)statcache.st_atime)));
  852.     (void)astore(ary,++sp,
  853.       str_2mortal(str_nmake((double)statcache.st_mtime)));
  854.     (void)astore(ary,++sp,
  855.       str_2mortal(str_nmake((double)statcache.st_ctime)));
  856. #ifdef STATBLOCKS
  857.     (void)astore(ary,++sp,
  858.       str_2mortal(str_nmake((double)statcache.st_blksize)));
  859.     (void)astore(ary,++sp,
  860.       str_2mortal(str_nmake((double)statcache.st_blocks)));
  861. #else
  862.     (void)astore(ary,++sp,
  863.       str_2mortal(str_make("",0)));
  864.     (void)astore(ary,++sp,
  865.       str_2mortal(str_make("",0)));
  866. #endif
  867. #else /* lint */
  868.     (void)astore(ary,++sp,str_nmake(0.0));
  869. #endif /* lint */
  870.     }
  871.     return sp;
  872. }
  873.  
  874. #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
  875.     /* code courtesy of William Kucharski */
  876. #define HAS_CHSIZE
  877.  
  878. int chsize(fd, length)
  879. int fd;            /* file descriptor */
  880. off_t length;        /* length to set file to */
  881. {
  882.     extern long lseek();
  883.     struct flock fl;
  884.     struct stat filebuf;
  885.  
  886.     if (fstat(fd, &filebuf) < 0)
  887.     return -1;
  888.  
  889.     if (filebuf.st_size < length) {
  890.  
  891.     /* extend file length */
  892.  
  893.     if ((lseek(fd, (length - 1), 0)) < 0)
  894.         return -1;
  895.  
  896.     /* write a "0" byte */
  897.  
  898.     if ((write(fd, "", 1)) != 1)
  899.         return -1;
  900.     }
  901.     else {
  902.     /* truncate length */
  903.  
  904.     fl.l_whence = 0;
  905.     fl.l_len = 0;
  906.     fl.l_start = length;
  907.     fl.l_type = F_WRLCK;    /* write lock on file space */
  908.  
  909.     /*
  910.     * This relies on the UNDOCUMENTED F_FREESP argument to
  911.     * fcntl(2), which truncates the file so that it ends at the
  912.     * position indicated by fl.l_start.
  913.     *
  914.     * Will minor miracles never cease?
  915.     */
  916.  
  917.     if (fcntl(fd, F_FREESP, &fl) < 0)
  918.         return -1;
  919.  
  920.     }
  921.  
  922.     return 0;
  923. }
  924. #endif /* F_FREESP */
  925.  
  926. int                    /*SUPPRESS 590*/
  927. do_truncate(str,arg,gimme,arglast)
  928. STR *str;
  929. register ARG *arg;
  930. int gimme;
  931. int *arglast;
  932. {
  933.     register ARRAY *ary = stack;
  934.     register int sp = arglast[0] + 1;
  935.     off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
  936.     int result = 1;
  937.     STAB *tmpstab;
  938.  
  939. #if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
  940. #ifdef HAS_TRUNCATE
  941.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  942.     tmpstab = arg[1].arg_ptr.arg_stab;
  943.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  944.       ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
  945.         result = 0;
  946.     }
  947.     else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
  948.     result = 0;
  949. #else
  950.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  951.     tmpstab = arg[1].arg_ptr.arg_stab;
  952.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  953.       chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
  954.         result = 0;
  955.     }
  956.     else {
  957.     int tmpfd;
  958.  
  959.     if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
  960.         result = 0;
  961.     else {
  962.         if (chsize(tmpfd, len) < 0)
  963.         result = 0;
  964.         close(tmpfd);
  965.     }
  966.     }
  967. #endif
  968.  
  969.     if (result)
  970.     str_sset(str,&str_yes);
  971.     else
  972.     str_sset(str,&str_undef);
  973.     STABSET(str);
  974.     ary->ary_array[sp] = str;
  975.     return sp;
  976. #else
  977.     fatal("truncate not implemented");
  978. #endif
  979. }
  980.  
  981. int
  982. looks_like_number(str)
  983. STR *str;
  984. {
  985.     register char *s;
  986.     register char *send;
  987.  
  988.     if (!str->str_pok)
  989.     return TRUE;
  990.     s = str->str_ptr; 
  991.     send = s + str->str_cur;
  992.     while (isSPACE(*s))
  993.     s++;
  994.     if (s >= send)
  995.     return FALSE;
  996.     if (*s == '+' || *s == '-')
  997.     s++;
  998.     while (isDIGIT(*s))
  999.     s++;
  1000.     if (s == send)
  1001.     return TRUE;
  1002.     if (*s == '.') 
  1003.     s++;
  1004.     else if (s == str->str_ptr)
  1005.     return FALSE;
  1006.     while (isDIGIT(*s))
  1007.     s++;
  1008.     if (s == send)
  1009.     return TRUE;
  1010.     if (*s == 'e' || *s == 'E') {
  1011.     s++;
  1012.     if (*s == '+' || *s == '-')
  1013.         s++;
  1014.     while (isDIGIT(*s))
  1015.         s++;
  1016.     }
  1017.     while (isSPACE(*s))
  1018.     s++;
  1019.     if (s >= send)
  1020.     return TRUE;
  1021.     return FALSE;
  1022. }
  1023.  
  1024. bool
  1025. do_print(str,fp)
  1026. register STR *str;
  1027. FILE *fp;
  1028. {
  1029.     register char *tmps;
  1030.  
  1031.     if (!fp) {
  1032.     if (dowarn)
  1033.         warn("print to unopened file");
  1034.     errno = EBADF;
  1035.     return FALSE;
  1036.     }
  1037.     if (!str)
  1038.     return TRUE;
  1039.     if (ofmt &&
  1040.       ((str->str_nok && str->str_u.str_nval != 0.0)
  1041.        || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
  1042.     fprintf(fp, ofmt, str->str_u.str_nval);
  1043.     return !ferror(fp);
  1044.     }
  1045.     else {
  1046.     tmps = str_get(str);
  1047.     if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
  1048.       && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
  1049.         STR *tmpstr = str_mortal(&str_undef);
  1050.         stab_efullname(tmpstr,((STAB*)str));/* a stab value, be nice */
  1051.         str = tmpstr;
  1052.         tmps = str->str_ptr;
  1053.         putc('*',fp);
  1054.     }
  1055.     if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
  1056.         return FALSE;
  1057.     }
  1058.     return TRUE;
  1059. }
  1060.  
  1061. bool
  1062. do_aprint(arg,fp,arglast)
  1063. register ARG *arg;
  1064. register FILE *fp;
  1065. int *arglast;
  1066. {
  1067.     register STR **st = stack->ary_array;
  1068.     register int sp = arglast[1];
  1069.     register int retval;
  1070.     register int items = arglast[2] - sp;
  1071.  
  1072.     if (!fp) {
  1073.     if (dowarn)
  1074.         warn("print to unopened file");
  1075.     errno = EBADF;
  1076.     return FALSE;
  1077.     }
  1078.     st += ++sp;
  1079.     if (arg->arg_type == O_PRTF) {
  1080.     do_sprintf(arg->arg_ptr.arg_str,items,st);
  1081.     retval = do_print(arg->arg_ptr.arg_str,fp);
  1082.     }
  1083.     else {
  1084.     retval = (items <= 0);
  1085.     for (; items > 0; items--,st++) {
  1086.         if (retval && ofslen) {
  1087.         if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
  1088.             retval = FALSE;
  1089.             break;
  1090.         }
  1091.         }
  1092.         if (!(retval = do_print(*st, fp)))
  1093.         break;
  1094.     }
  1095.     if (retval && orslen)
  1096.         if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
  1097.         retval = FALSE;
  1098.     }
  1099.     return retval;
  1100. }
  1101.  
  1102. int
  1103. mystat(arg,str)
  1104. ARG *arg;
  1105. STR *str;
  1106. {
  1107.     STIO *stio;
  1108.  
  1109.     if (arg[1].arg_type & A_DONT) {
  1110.     stio = stab_io(arg[1].arg_ptr.arg_stab);
  1111.     if (stio && stio->ifp) {
  1112.         statstab = arg[1].arg_ptr.arg_stab;
  1113.         str_set(statname,"");
  1114.         laststype = O_STAT;
  1115.         return (laststatval = fstat(fileno(stio->ifp), &statcache));
  1116.     }
  1117.     else {
  1118.         if (arg[1].arg_ptr.arg_stab == defstab)
  1119.         return laststatval;
  1120.         if (dowarn)
  1121.         warn("Stat on unopened file <%s>",
  1122.           stab_ename(arg[1].arg_ptr.arg_stab));
  1123.         statstab = Nullstab;
  1124.         str_set(statname,"");
  1125.         return (laststatval = -1);
  1126.     }
  1127.     }
  1128.     else {
  1129.     statstab = Nullstab;
  1130.     str_set(statname,str_get(str));
  1131.     laststype = O_STAT;
  1132.     laststatval = stat(str_get(str),&statcache);
  1133.     if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
  1134.         warn(warn_nl, "stat");
  1135.     return laststatval;
  1136.     }
  1137. }
  1138.  
  1139. int
  1140. mylstat(arg,str)
  1141. ARG *arg;
  1142. STR *str;
  1143. {
  1144.     if (arg[1].arg_type & A_DONT) {
  1145.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1146.         if (laststype != O_LSTAT)
  1147.         fatal("The stat preceding -l _ wasn't an lstat");
  1148.         return laststatval;
  1149.     }
  1150.     fatal("You can't use -l on a filehandle");
  1151.     }
  1152.  
  1153.     laststype = O_LSTAT;
  1154.     statstab = Nullstab;
  1155.     str_set(statname,str_get(str));
  1156. #ifdef HAS_LSTAT
  1157.     laststatval = lstat(str_get(str),&statcache);
  1158. #else
  1159.     laststatval = stat(str_get(str),&statcache);
  1160. #endif
  1161.     if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
  1162.     warn(warn_nl, "lstat");
  1163.     return laststatval;
  1164. }
  1165.  
  1166. STR *
  1167. do_fttext(arg,str)
  1168. register ARG *arg;
  1169. STR *str;
  1170. {
  1171.     int i;
  1172.     int len;
  1173.     int odd = 0;
  1174.     STDCHAR tbuf[512];
  1175.     register STDCHAR *s;
  1176.     register STIO *stio;
  1177.  
  1178.     if (arg[1].arg_type & A_DONT) {
  1179.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1180.         if (statstab)
  1181.         stio = stab_io(statstab);
  1182.         else {
  1183.         str = statname;
  1184.         goto really_filename;
  1185.         }
  1186.     }
  1187.     else {
  1188.         statstab = arg[1].arg_ptr.arg_stab;
  1189.         str_set(statname,"");
  1190.         stio = stab_io(statstab);
  1191.     }
  1192.     if (stio && stio->ifp) {
  1193. #if defined(STDSTDIO) || defined(atarist) /* this will work with atariST */
  1194.         fstat(fileno(stio->ifp),&statcache);
  1195.         if (S_ISDIR(statcache.st_mode))    /* handle NFS glitch */
  1196.         return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
  1197.         if (stio->ifp->_cnt <= 0) {
  1198.         i = getc(stio->ifp);
  1199.         if (i != EOF)
  1200.             (void)ungetc(i,stio->ifp);
  1201.         }
  1202.         if (stio->ifp->_cnt <= 0)    /* null file is anything */
  1203.         return &str_yes;
  1204.         len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
  1205.         s = stio->ifp->_base;
  1206. #else
  1207.         fatal("-T and -B not implemented on filehandles");
  1208. #endif
  1209.     }
  1210.     else {
  1211.         if (dowarn)
  1212.         warn("Test on unopened file <%s>",
  1213.           stab_ename(arg[1].arg_ptr.arg_stab));
  1214.         errno = EBADF;
  1215.         return &str_undef;
  1216.     }
  1217.     }
  1218.     else {
  1219.     statstab = Nullstab;
  1220.     str_set(statname,str_get(str));
  1221.       really_filename:
  1222.     i = open(str_get(str),0);
  1223.     if (i < 0) {
  1224.         if (dowarn && index(str_get(str), '\n'))
  1225.         warn(warn_nl, "open");
  1226.         return &str_undef;
  1227.     }
  1228.     fstat(i,&statcache);
  1229.     len = read(i,tbuf,512);
  1230.     (void)close(i);
  1231.     if (len <= 0) {
  1232.         if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
  1233.         return &str_no;        /* special case NFS directories */
  1234.         return &str_yes;        /* null file is anything */
  1235.     }
  1236.     s = tbuf;
  1237.     }
  1238.  
  1239.     /* now scan s to look for textiness */
  1240.  
  1241.     for (i = 0; i < len; i++,s++) {
  1242.     if (!*s) {            /* null never allowed in text */
  1243.         odd += len;
  1244.         break;
  1245.     }
  1246.     else if (*s & 128)
  1247.         odd++;
  1248.     else if (*s < 32 &&
  1249.       *s != '\n' && *s != '\r' && *s != '\b' &&
  1250.       *s != '\t' && *s != '\f' && *s != 27)
  1251.         odd++;
  1252.     }
  1253.  
  1254.     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
  1255.     return &str_no;
  1256.     else
  1257.     return &str_yes;
  1258. }
  1259.  
  1260. static char **Argv = Null(char **);
  1261. static char *Cmd = Nullch;
  1262.  
  1263. bool
  1264. do_aexec(really,arglast)
  1265. STR *really;
  1266. int *arglast;
  1267. {
  1268.     register STR **st = stack->ary_array;
  1269.     register int sp = arglast[1];
  1270.     register int items = arglast[2] - sp;
  1271.     register char **a;
  1272.     char *tmps;
  1273.  
  1274.     if (items) {
  1275.     New(401,Argv, items+1, char*);
  1276.     a = Argv;
  1277.     for (st += ++sp; items > 0; items--,st++) {
  1278.         if (*st)
  1279.         *a++ = str_get(*st);
  1280.         else
  1281.         *a++ = "";
  1282.     }
  1283.     *a = Nullch;
  1284. #ifdef TAINT
  1285.     if (*Argv[0] != '/')    /* will execvp use PATH? */
  1286.         taintenv();        /* testing IFS here is overkill, probably */
  1287. #endif
  1288. #ifdef DJGPP
  1289.     fatal("exec not supported - H.Doi");
  1290. #else
  1291.     if (really && *(tmps = str_get(really)))
  1292.         execvp(tmps,Argv);
  1293.     else
  1294.         execvp(Argv[0],Argv);
  1295. #endif /* DJGPP */
  1296.     }
  1297.     do_execfree();
  1298.     return FALSE;
  1299. }
  1300.  
  1301. void
  1302. do_execfree()
  1303. {
  1304.     if (Argv) {
  1305.     Safefree(Argv);
  1306.     Argv = Null(char **);
  1307.     }
  1308.     if (Cmd) {
  1309.     Safefree(Cmd);
  1310.     Cmd = Nullch;
  1311.     }
  1312. }
  1313.  
  1314. bool
  1315. do_exec(cmd)
  1316. char *cmd;
  1317. {
  1318.     register char **a;
  1319.     register char *s;
  1320.     char flags[10];
  1321.  
  1322.     /* save an extra exec if possible */
  1323.  
  1324. #ifdef CSH
  1325.     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
  1326.     strcpy(flags,"-c");
  1327.     s = cmd+cshlen+3;
  1328.     if (*s == 'f') {
  1329.         s++;
  1330.         strcat(flags,"f");
  1331.     }
  1332.     if (*s == ' ')
  1333.         s++;
  1334.     if (*s++ == '\'') {
  1335.         char *ncmd = s;
  1336.  
  1337.         while (*s)
  1338.         s++;
  1339.         if (s[-1] == '\n')
  1340.         *--s = '\0';
  1341.         if (s[-1] == '\'') {
  1342.         *--s = '\0';
  1343. #ifdef DJGPP
  1344.         fatal("we don't have csh - H.Doi");
  1345. #else
  1346.         execl(cshname,"csh", flags,ncmd,(char*)0);
  1347. #endif /* DJGPP */
  1348.         *s = '\'';
  1349.         return FALSE;
  1350.         }
  1351.     }
  1352.     }
  1353. #endif /* CSH */
  1354.  
  1355.     /* see if there are shell metacharacters in it */
  1356.  
  1357.     /*SUPPRESS 530*/
  1358.     for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
  1359.     if (*s == '=')
  1360.     goto doshell;
  1361.     for (s = cmd; *s; s++) {
  1362.     if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
  1363.         if (*s == '\n' && !s[1]) {
  1364.         *s = '\0';
  1365.         break;
  1366.         }
  1367.       doshell:
  1368. #ifdef DJGPP
  1369.         system(cmd);
  1370.         exit(0);
  1371. #else
  1372.         execl("/bin/sh","sh","-c",cmd,(char*)0);
  1373. #endif /* DJGPP */
  1374.         return FALSE;
  1375.     }
  1376.     }
  1377.     New(402,Argv, (s - cmd) / 2 + 2, char*);
  1378.     Cmd = nsavestr(cmd, s-cmd);
  1379.     a = Argv;
  1380.     for (s = Cmd; *s;) {
  1381.     while (*s && isSPACE(*s)) s++;
  1382.     if (*s)
  1383.         *(a++) = s;
  1384.     while (*s && !isSPACE(*s)) s++;
  1385.     if (*s)
  1386.         *s++ = '\0';
  1387.     }
  1388.     *a = Nullch;
  1389.     if (Argv[0]) {
  1390. #ifdef DJGPP
  1391.     system(cmd);
  1392.     exit(0);
  1393. #else
  1394.     execvp(Argv[0],Argv);
  1395. #endif /* DJGPP */
  1396.     if (errno == ENOEXEC) {        /* for system V NIH syndrome */
  1397.         do_execfree();
  1398.         goto doshell;
  1399.     }
  1400.     }
  1401.     do_execfree();
  1402.     return FALSE;
  1403. }
  1404.  
  1405. #ifdef HAS_SOCKET
  1406. int
  1407. do_socket(stab, arglast)
  1408. STAB *stab;
  1409. int *arglast;
  1410. {
  1411.     register STR **st = stack->ary_array;
  1412.     register int sp = arglast[1];
  1413.     register STIO *stio;
  1414.     int domain, type, protocol, fd;
  1415.  
  1416.     if (!stab) {
  1417.     errno = EBADF;
  1418.     return FALSE;
  1419.     }
  1420.  
  1421.     stio = stab_io(stab);
  1422.     if (!stio)
  1423.     stio = stab_io(stab) = stio_new();
  1424.     else if (stio->ifp)
  1425.     do_close(stab,FALSE);
  1426.  
  1427.     domain = (int)str_gnum(st[++sp]);
  1428.     type = (int)str_gnum(st[++sp]);
  1429.     protocol = (int)str_gnum(st[++sp]);
  1430. #ifdef TAINT
  1431.     taintproper("Insecure dependency in socket");
  1432. #endif
  1433.     fd = socket(domain,type,protocol);
  1434.     if (fd < 0)
  1435.     return FALSE;
  1436.     stio->ifp = fdopen(fd, "r");    /* stdio gets confused about sockets */
  1437.     stio->ofp = fdopen(fd, "w");
  1438.     stio->type = 's';
  1439.     if (!stio->ifp || !stio->ofp) {
  1440.     if (stio->ifp) fclose(stio->ifp);
  1441.     if (stio->ofp) fclose(stio->ofp);
  1442.     if (!stio->ifp && !stio->ofp) close(fd);
  1443.     return FALSE;
  1444.     }
  1445.  
  1446.     return TRUE;
  1447. }
  1448.  
  1449. int
  1450. do_bind(stab, arglast)
  1451. STAB *stab;
  1452. int *arglast;
  1453. {
  1454.     register STR **st = stack->ary_array;
  1455.     register int sp = arglast[1];
  1456.     register STIO *stio;
  1457.     char *addr;
  1458.  
  1459.     if (!stab)
  1460.     goto nuts;
  1461.  
  1462.     stio = stab_io(stab);
  1463.     if (!stio || !stio->ifp)
  1464.     goto nuts;
  1465.  
  1466.     addr = str_get(st[++sp]);
  1467. #ifdef TAINT
  1468.     taintproper("Insecure dependency in bind");
  1469. #endif
  1470.     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1471.  
  1472. nuts:
  1473.     if (dowarn)
  1474.     warn("bind() on closed fd");
  1475.     errno = EBADF;
  1476.     return FALSE;
  1477.  
  1478. }
  1479.  
  1480. int
  1481. do_connect(stab, arglast)
  1482. STAB *stab;
  1483. int *arglast;
  1484. {
  1485.     register STR **st = stack->ary_array;
  1486.     register int sp = arglast[1];
  1487.     register STIO *stio;
  1488.     char *addr;
  1489.  
  1490.     if (!stab)
  1491.     goto nuts;
  1492.  
  1493.     stio = stab_io(stab);
  1494.     if (!stio || !stio->ifp)
  1495.     goto nuts;
  1496.  
  1497.     addr = str_get(st[++sp]);
  1498. #ifdef TAINT
  1499.     taintproper("Insecure dependency in connect");
  1500. #endif
  1501.     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1502.  
  1503. nuts:
  1504.     if (dowarn)
  1505.     warn("connect() on closed fd");
  1506.     errno = EBADF;
  1507.     return FALSE;
  1508.  
  1509. }
  1510.  
  1511. int
  1512. do_listen(stab, arglast)
  1513. STAB *stab;
  1514. int *arglast;
  1515. {
  1516.     register STR **st = stack->ary_array;
  1517.     register int sp = arglast[1];
  1518.     register STIO *stio;
  1519.     int backlog;
  1520.  
  1521.     if (!stab)
  1522.     goto nuts;
  1523.  
  1524.     stio = stab_io(stab);
  1525.     if (!stio || !stio->ifp)
  1526.     goto nuts;
  1527.  
  1528.     backlog = (int)str_gnum(st[++sp]);
  1529.     return listen(fileno(stio->ifp), backlog) >= 0;
  1530.  
  1531. nuts:
  1532.     if (dowarn)
  1533.     warn("listen() on closed fd");
  1534.     errno = EBADF;
  1535.     return FALSE;
  1536. }
  1537.  
  1538. void
  1539. do_accept(str, nstab, gstab)
  1540. STR *str;
  1541. STAB *nstab;
  1542. STAB *gstab;
  1543. {
  1544.     register STIO *nstio;
  1545.     register STIO *gstio;
  1546.     int len = sizeof buf;
  1547.     int fd;
  1548.  
  1549.     if (!nstab)
  1550.     goto badexit;
  1551.     if (!gstab)
  1552.     goto nuts;
  1553.  
  1554.     gstio = stab_io(gstab);
  1555.     nstio = stab_io(nstab);
  1556.  
  1557.     if (!gstio || !gstio->ifp)
  1558.     goto nuts;
  1559.     if (!nstio)
  1560.     nstio = stab_io(nstab) = stio_new();
  1561.     else if (nstio->ifp)
  1562.     do_close(nstab,FALSE);
  1563.  
  1564.     fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
  1565.     if (fd < 0)
  1566.     goto badexit;
  1567.     nstio->ifp = fdopen(fd, "r");
  1568.     nstio->ofp = fdopen(fd, "w");
  1569.     nstio->type = 's';
  1570.     if (!nstio->ifp || !nstio->ofp) {
  1571.     if (nstio->ifp) fclose(nstio->ifp);
  1572.     if (nstio->ofp) fclose(nstio->ofp);
  1573.     if (!nstio->ifp && !nstio->ofp) close(fd);
  1574.     goto badexit;
  1575.     }
  1576.  
  1577.     str_nset(str, buf, len);
  1578.     return;
  1579.  
  1580. nuts:
  1581.     if (dowarn)
  1582.     warn("accept() on closed fd");
  1583.     errno = EBADF;
  1584. badexit:
  1585.     str_sset(str,&str_undef);
  1586.     return;
  1587. }
  1588.  
  1589. int
  1590. do_shutdown(stab, arglast)
  1591. STAB *stab;
  1592. int *arglast;
  1593. {
  1594.     register STR **st = stack->ary_array;
  1595.     register int sp = arglast[1];
  1596.     register STIO *stio;
  1597.     int how;
  1598.  
  1599.     if (!stab)
  1600.     goto nuts;
  1601.  
  1602.     stio = stab_io(stab);
  1603.     if (!stio || !stio->ifp)
  1604.     goto nuts;
  1605.  
  1606.     how = (int)str_gnum(st[++sp]);
  1607.     return shutdown(fileno(stio->ifp), how) >= 0;
  1608.  
  1609. nuts:
  1610.     if (dowarn)
  1611.     warn("shutdown() on closed fd");
  1612.     errno = EBADF;
  1613.     return FALSE;
  1614.  
  1615. }
  1616.  
  1617. int
  1618. do_sopt(optype, stab, arglast)
  1619. int optype;
  1620. STAB *stab;
  1621. int *arglast;
  1622. {
  1623.     register STR **st = stack->ary_array;
  1624.     register int sp = arglast[1];
  1625.     register STIO *stio;
  1626.     int fd;
  1627.     unsigned int lvl;
  1628.     unsigned int optname;
  1629.  
  1630.     if (!stab)
  1631.     goto nuts;
  1632.  
  1633.     stio = stab_io(stab);
  1634.     if (!stio || !stio->ifp)
  1635.     goto nuts;
  1636.  
  1637.     fd = fileno(stio->ifp);
  1638.     lvl = (unsigned int)str_gnum(st[sp+1]);
  1639.     optname = (unsigned int)str_gnum(st[sp+2]);
  1640.     switch (optype) {
  1641.     case O_GSOCKOPT:
  1642.     st[sp] = str_2mortal(Str_new(22,257));
  1643.     st[sp]->str_cur = 256;
  1644.     st[sp]->str_pok = 1;
  1645.     if (getsockopt(fd, lvl, optname, st[sp]->str_ptr,
  1646.             (int*)&st[sp]->str_cur) < 0)
  1647.         goto nuts;
  1648.     break;
  1649.     case O_SSOCKOPT:
  1650.     st[sp] = st[sp+3];
  1651.     if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
  1652.         goto nuts;
  1653.     st[sp] = &str_yes;
  1654.     break;
  1655.     }
  1656.     
  1657.     return sp;
  1658.  
  1659. nuts:
  1660.     if (dowarn)
  1661.     warn("[gs]etsockopt() on closed fd");
  1662.     st[sp] = &str_undef;
  1663.     errno = EBADF;
  1664.     return sp;
  1665.  
  1666. }
  1667.  
  1668. int
  1669. do_getsockname(optype, stab, arglast)
  1670. int optype;
  1671. STAB *stab;
  1672. int *arglast;
  1673. {
  1674.     register STR **st = stack->ary_array;
  1675.     register int sp = arglast[1];
  1676.     register STIO *stio;
  1677.     int fd;
  1678.  
  1679.     if (!stab)
  1680.     goto nuts;
  1681.  
  1682.     stio = stab_io(stab);
  1683.     if (!stio || !stio->ifp)
  1684.     goto nuts;
  1685.  
  1686.     st[sp] = str_2mortal(Str_new(22,257));
  1687.     st[sp]->str_cur = 256;
  1688.     st[sp]->str_pok = 1;
  1689.     fd = fileno(stio->ifp);
  1690.     switch (optype) {
  1691.     case O_GETSOCKNAME:
  1692.     if (getsockname(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1693.         goto nuts2;
  1694.     break;
  1695.     case O_GETPEERNAME:
  1696.     if (getpeername(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1697.         goto nuts2;
  1698.     break;
  1699.     }
  1700.     
  1701.     return sp;
  1702.  
  1703. nuts:
  1704.     if (dowarn)
  1705.     warn("get{sock,peer}name() on closed fd");
  1706.     errno = EBADF;
  1707. nuts2:
  1708.     st[sp] = &str_undef;
  1709.     return sp;
  1710.  
  1711. }
  1712.  
  1713. int
  1714. do_ghent(which,gimme,arglast)
  1715. int which;
  1716. int gimme;
  1717. int *arglast;
  1718. {
  1719.     register ARRAY *ary = stack;
  1720.     register int sp = arglast[0];
  1721.     register char **elem;
  1722.     register STR *str;
  1723.     struct hostent *gethostbyname();
  1724.     struct hostent *gethostbyaddr();
  1725. #ifdef HAS_GETHOSTENT
  1726.     struct hostent *gethostent();
  1727. #endif
  1728.     struct hostent *hent;
  1729.     unsigned long len;
  1730.  
  1731.     if (which == O_GHBYNAME) {
  1732.     char *name = str_get(ary->ary_array[sp+1]);
  1733.  
  1734.     hent = gethostbyname(name);
  1735.     }
  1736.     else if (which == O_GHBYADDR) {
  1737.     STR *addrstr = ary->ary_array[sp+1];
  1738.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1739.     char *addr = str_get(addrstr);
  1740.  
  1741.     hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
  1742.     }
  1743.     else
  1744. #ifdef HAS_GETHOSTENT
  1745.     hent = gethostent();
  1746. #else
  1747.     fatal("gethostent not implemented");
  1748. #endif
  1749.  
  1750. #ifdef HOST_NOT_FOUND
  1751.     if (!hent)
  1752.     statusvalue = (unsigned short)h_errno & 0xffff;
  1753. #endif
  1754.  
  1755.     if (gimme != G_ARRAY) {
  1756.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1757.     if (hent) {
  1758.         if (which == O_GHBYNAME) {
  1759. #ifdef h_addr
  1760.         str_nset(str, *hent->h_addr, hent->h_length);
  1761. #else
  1762.         str_nset(str, hent->h_addr, hent->h_length);
  1763. #endif
  1764.         }
  1765.         else
  1766.         str_set(str, hent->h_name);
  1767.     }
  1768.     return sp;
  1769.     }
  1770.  
  1771.     if (hent) {
  1772. #ifndef lint
  1773.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1774.     str_set(str, hent->h_name);
  1775.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1776.     for (elem = hent->h_aliases; *elem; elem++) {
  1777.         str_cat(str, *elem);
  1778.         if (elem[1])
  1779.         str_ncat(str," ",1);
  1780.     }
  1781.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1782.     str_numset(str, (double)hent->h_addrtype);
  1783.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1784.     len = hent->h_length;
  1785.     str_numset(str, (double)len);
  1786. #ifdef h_addr
  1787.     for (elem = hent->h_addr_list; *elem; elem++) {
  1788.         (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1789.         str_nset(str, *elem, len);
  1790.     }
  1791. #else
  1792.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1793.     str_nset(str, hent->h_addr, len);
  1794. #endif /* h_addr */
  1795. #else /* lint */
  1796.     elem = Nullch;
  1797.     elem = elem;
  1798.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1799. #endif /* lint */
  1800.     }
  1801.  
  1802.     return sp;
  1803. }
  1804.  
  1805. int
  1806. do_gnent(which,gimme,arglast)
  1807. int which;
  1808. int gimme;
  1809. int *arglast;
  1810. {
  1811.     register ARRAY *ary = stack;
  1812.     register int sp = arglast[0];
  1813.     register char **elem;
  1814.     register STR *str;
  1815.     struct netent *getnetbyname();
  1816.     struct netent *getnetbyaddr();
  1817.     struct netent *getnetent();
  1818.     struct netent *nent;
  1819.  
  1820.     if (which == O_GNBYNAME) {
  1821.     char *name = str_get(ary->ary_array[sp+1]);
  1822.  
  1823.     nent = getnetbyname(name);
  1824.     }
  1825.     else if (which == O_GNBYADDR) {
  1826.     unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
  1827.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1828.  
  1829.     nent = getnetbyaddr((long)addr,addrtype);
  1830.     }
  1831.     else
  1832.     nent = getnetent();
  1833.  
  1834.     if (gimme != G_ARRAY) {
  1835.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1836.     if (nent) {
  1837.         if (which == O_GNBYNAME)
  1838.         str_numset(str, (double)nent->n_net);
  1839.         else
  1840.         str_set(str, nent->n_name);
  1841.     }
  1842.     return sp;
  1843.     }
  1844.  
  1845.     if (nent) {
  1846. #ifndef lint
  1847.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1848.     str_set(str, nent->n_name);
  1849.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1850.     for (elem = nent->n_aliases; *elem; elem++) {
  1851.         str_cat(str, *elem);
  1852.         if (elem[1])
  1853.         str_ncat(str," ",1);
  1854.     }
  1855.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1856.     str_numset(str, (double)nent->n_addrtype);
  1857.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1858.     str_numset(str, (double)nent->n_net);
  1859. #else /* lint */
  1860.     elem = Nullch;
  1861.     elem = elem;
  1862.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1863. #endif /* lint */
  1864.     }
  1865.  
  1866.     return sp;
  1867. }
  1868.  
  1869. int
  1870. do_gpent(which,gimme,arglast)
  1871. int which;
  1872. int gimme;
  1873. int *arglast;
  1874. {
  1875.     register ARRAY *ary = stack;
  1876.     register int sp = arglast[0];
  1877.     register char **elem;
  1878.     register STR *str;
  1879.     struct protoent *getprotobyname();
  1880.     struct protoent *getprotobynumber();
  1881.     struct protoent *getprotoent();
  1882.     struct protoent *pent;
  1883.  
  1884.     if (which == O_GPBYNAME) {
  1885.     char *name = str_get(ary->ary_array[sp+1]);
  1886.  
  1887.     pent = getprotobyname(name);
  1888.     }
  1889.     else if (which == O_GPBYNUMBER) {
  1890.     int proto = (int)str_gnum(ary->ary_array[sp+1]);
  1891.  
  1892.     pent = getprotobynumber(proto);
  1893.     }
  1894.     else
  1895.     pent = getprotoent();
  1896.  
  1897.     if (gimme != G_ARRAY) {
  1898.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1899.     if (pent) {
  1900.         if (which == O_GPBYNAME)
  1901.         str_numset(str, (double)pent->p_proto);
  1902.         else
  1903.         str_set(str, pent->p_name);
  1904.     }
  1905.     return sp;
  1906.     }
  1907.  
  1908.     if (pent) {
  1909. #ifndef lint
  1910.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1911.     str_set(str, pent->p_name);
  1912.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1913.     for (elem = pent->p_aliases; *elem; elem++) {
  1914.         str_cat(str, *elem);
  1915.         if (elem[1])
  1916.         str_ncat(str," ",1);
  1917.     }
  1918.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1919.     str_numset(str, (double)pent->p_proto);
  1920. #else /* lint */
  1921.     elem = Nullch;
  1922.     elem = elem;
  1923.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1924. #endif /* lint */
  1925.     }
  1926.  
  1927.     return sp;
  1928. }
  1929.  
  1930. int
  1931. do_gsent(which,gimme,arglast)
  1932. int which;
  1933. int gimme;
  1934. int *arglast;
  1935. {
  1936.     register ARRAY *ary = stack;
  1937.     register int sp = arglast[0];
  1938.     register char **elem;
  1939.     register STR *str;
  1940.     struct servent *getservbyname();
  1941.     struct servent *getservbynumber();
  1942.     struct servent *getservent();
  1943.     struct servent *sent;
  1944.  
  1945.     if (which == O_GSBYNAME) {
  1946.     char *name = str_get(ary->ary_array[sp+1]);
  1947.     char *proto = str_get(ary->ary_array[sp+2]);
  1948.  
  1949.     if (proto && !*proto)
  1950.         proto = Nullch;
  1951.  
  1952.     sent = getservbyname(name,proto);
  1953.     }
  1954.     else if (which == O_GSBYPORT) {
  1955.     int port = (int)str_gnum(ary->ary_array[sp+1]);
  1956.     char *proto = str_get(ary->ary_array[sp+2]);
  1957.  
  1958.     sent = getservbyport(port,proto);
  1959.     }
  1960.     else
  1961.     sent = getservent();
  1962.  
  1963.     if (gimme != G_ARRAY) {
  1964.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1965.     if (sent) {
  1966.         if (which == O_GSBYNAME) {
  1967. #ifdef HAS_NTOHS
  1968.         str_numset(str, (double)ntohs(sent->s_port));
  1969. #else
  1970.         str_numset(str, (double)(sent->s_port));
  1971. #endif
  1972.         }
  1973.         else
  1974.         str_set(str, sent->s_name);
  1975.     }
  1976.     return sp;
  1977.     }
  1978.  
  1979.     if (sent) {
  1980. #ifndef lint
  1981.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1982.     str_set(str, sent->s_name);
  1983.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1984.     for (elem = sent->s_aliases; *elem; elem++) {
  1985.         str_cat(str, *elem);
  1986.         if (elem[1])
  1987.         str_ncat(str," ",1);
  1988.     }
  1989.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1990. #ifdef HAS_NTOHS
  1991.     str_numset(str, (double)ntohs(sent->s_port));
  1992. #else
  1993.     str_numset(str, (double)(sent->s_port));
  1994. #endif
  1995.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1996.     str_set(str, sent->s_proto);
  1997. #else /* lint */
  1998.     elem = Nullch;
  1999.     elem = elem;
  2000.     (void)astore(ary, ++sp, str_mortal(&str_no));
  2001. #endif /* lint */
  2002.     }
  2003.  
  2004.     return sp;
  2005. }
  2006.  
  2007. #endif /* HAS_SOCKET */
  2008.  
  2009. #ifdef HAS_SELECT
  2010. int
  2011. do_select(gimme,arglast)
  2012. int gimme;
  2013. int *arglast;
  2014. {
  2015.     register STR **st = stack->ary_array;
  2016.     register int sp = arglast[0];
  2017.     register int i;
  2018.     register int j;
  2019.     register char *s;
  2020.     register STR *str;
  2021.     double value;
  2022.     int maxlen = 0;
  2023.     int nfound;
  2024.     struct timeval timebuf;
  2025.     struct timeval *tbuf = &timebuf;
  2026.     int growsize;
  2027. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2028.     int masksize;
  2029.     int offset;
  2030.     char *fd_sets[4];
  2031.     int k;
  2032.  
  2033. #if BYTEORDER & 0xf0000
  2034. #define ORDERBYTE (0x88888888 - BYTEORDER)
  2035. #else
  2036. #define ORDERBYTE (0x4444 - BYTEORDER)
  2037. #endif
  2038.  
  2039. #endif
  2040.  
  2041.     for (i = 1; i <= 3; i++) {
  2042.     j = st[sp+i]->str_cur;
  2043.     if (maxlen < j)
  2044.         maxlen = j;
  2045.     }
  2046.  
  2047. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2048.     growsize = maxlen;        /* little endians can use vecs directly */
  2049. #else
  2050. #ifdef NFDBITS
  2051.  
  2052. #ifndef NBBY
  2053. #define NBBY 8
  2054. #endif
  2055.  
  2056.     masksize = NFDBITS / NBBY;
  2057. #else
  2058.     masksize = sizeof(long);    /* documented int, everyone seems to use long */
  2059. #endif
  2060.     growsize = maxlen + (masksize - (maxlen % masksize));
  2061.     Zero(&fd_sets[0], 4, char*);
  2062. #endif
  2063.  
  2064.     for (i = 1; i <= 3; i++) {
  2065.     str = st[sp+i];
  2066.     j = str->str_len;
  2067.     if (j < growsize) {
  2068.         if (str->str_pok) {
  2069.         Str_Grow(str,growsize);
  2070.         s = str_get(str) + j;
  2071.         while (++j <= growsize) {
  2072.             *s++ = '\0';
  2073.         }
  2074.         }
  2075.         else if (str->str_ptr) {
  2076.         Safefree(str->str_ptr);
  2077.         str->str_ptr = Nullch;
  2078.         }
  2079.     }
  2080. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2081.     s = str->str_ptr;
  2082.     if (s) {
  2083.         New(403, fd_sets[i], growsize, char);
  2084.         for (offset = 0; offset < growsize; offset += masksize) {
  2085.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2086.             fd_sets[i][j+offset] = s[(k % masksize) + offset];
  2087.         }
  2088.     }
  2089. #endif
  2090.     }
  2091.     str = st[sp+4];
  2092.     if (str->str_nok || str->str_pok) {
  2093.     value = str_gnum(str);
  2094.     if (value < 0.0)
  2095.         value = 0.0;
  2096.     timebuf.tv_sec = (long)value;
  2097.     value -= (double)timebuf.tv_sec;
  2098.     timebuf.tv_usec = (long)(value * 1000000.0);
  2099.     }
  2100.     else
  2101.     tbuf = Null(struct timeval*);
  2102.  
  2103. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2104.     nfound = select(
  2105.     maxlen * 8,
  2106.     st[sp+1]->str_ptr,
  2107.     st[sp+2]->str_ptr,
  2108.     st[sp+3]->str_ptr,
  2109.     tbuf);
  2110. #else
  2111.     nfound = select(
  2112.     maxlen * 8,
  2113.     fd_sets[1],
  2114.     fd_sets[2],
  2115.     fd_sets[3],
  2116.     tbuf);
  2117.     for (i = 1; i <= 3; i++) {
  2118.     if (fd_sets[i]) {
  2119.         str = st[sp+i];
  2120.         s = str->str_ptr;
  2121.         for (offset = 0; offset < growsize; offset += masksize) {
  2122.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2123.             s[(k % masksize) + offset] = fd_sets[i][j+offset];
  2124.         }
  2125.         Safefree(fd_sets[i]);
  2126.     }
  2127.     }
  2128. #endif
  2129.  
  2130.     st[++sp] = str_mortal(&str_no);
  2131.     str_numset(st[sp], (double)nfound);
  2132.     if (gimme == G_ARRAY && tbuf) {
  2133.     value = (double)(timebuf.tv_sec) +
  2134.         (double)(timebuf.tv_usec) / 1000000.0;
  2135.     st[++sp] = str_mortal(&str_no);
  2136.     str_numset(st[sp], value);
  2137.     }
  2138.     return sp;
  2139. }
  2140. #endif /* SELECT */
  2141.  
  2142. #ifdef HAS_SOCKET
  2143. int
  2144. do_spair(stab1, stab2, arglast)
  2145. STAB *stab1;
  2146. STAB *stab2;
  2147. int *arglast;
  2148. {
  2149.     register STR **st = stack->ary_array;
  2150.     register int sp = arglast[2];
  2151.     register STIO *stio1;
  2152.     register STIO *stio2;
  2153.     int domain, type, protocol, fd[2];
  2154.  
  2155.     if (!stab1 || !stab2)
  2156.     return FALSE;
  2157.  
  2158.     stio1 = stab_io(stab1);
  2159.     stio2 = stab_io(stab2);
  2160.     if (!stio1)
  2161.     stio1 = stab_io(stab1) = stio_new();
  2162.     else if (stio1->ifp)
  2163.     do_close(stab1,FALSE);
  2164.     if (!stio2)
  2165.     stio2 = stab_io(stab2) = stio_new();
  2166.     else if (stio2->ifp)
  2167.     do_close(stab2,FALSE);
  2168.  
  2169.     domain = (int)str_gnum(st[++sp]);
  2170.     type = (int)str_gnum(st[++sp]);
  2171.     protocol = (int)str_gnum(st[++sp]);
  2172. #ifdef TAINT
  2173.     taintproper("Insecure dependency in socketpair");
  2174. #endif
  2175. #ifdef HAS_SOCKETPAIR
  2176.     if (socketpair(domain,type,protocol,fd) < 0)
  2177.     return FALSE;
  2178. #else
  2179.     fatal("Socketpair unimplemented");
  2180. #endif
  2181.     stio1->ifp = fdopen(fd[0], "r");
  2182.     stio1->ofp = fdopen(fd[0], "w");
  2183.     stio1->type = 's';
  2184.     stio2->ifp = fdopen(fd[1], "r");
  2185.     stio2->ofp = fdopen(fd[1], "w");
  2186.     stio2->type = 's';
  2187.     if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
  2188.     if (stio1->ifp) fclose(stio1->ifp);
  2189.     if (stio1->ofp) fclose(stio1->ofp);
  2190.     if (!stio1->ifp && !stio1->ofp) close(fd[0]);
  2191.     if (stio2->ifp) fclose(stio2->ifp);
  2192.     if (stio2->ofp) fclose(stio2->ofp);
  2193.     if (!stio2->ifp && !stio2->ofp) close(fd[1]);
  2194.     return FALSE;
  2195.     }
  2196.  
  2197.     return TRUE;
  2198. }
  2199.  
  2200. #endif /* HAS_SOCKET */
  2201.  
  2202. int
  2203. do_gpwent(which,gimme,arglast)
  2204. int which;
  2205. int gimme;
  2206. int *arglast;
  2207. {
  2208. #ifdef I_PWD
  2209.     register ARRAY *ary = stack;
  2210.     register int sp = arglast[0];
  2211.     register STR *str;
  2212.     struct passwd *getpwnam();
  2213.     struct passwd *getpwuid();
  2214.     struct passwd *getpwent();
  2215.     struct passwd *pwent;
  2216.  
  2217.     if (which == O_GPWNAM) {
  2218.     char *name = str_get(ary->ary_array[sp+1]);
  2219.  
  2220.     pwent = getpwnam(name);
  2221.     }
  2222.     else if (which == O_GPWUID) {
  2223.     int uid = (int)str_gnum(ary->ary_array[sp+1]);
  2224.  
  2225.     pwent = getpwuid(uid);
  2226.     }
  2227.     else
  2228.     pwent = getpwent();
  2229.  
  2230.     if (gimme != G_ARRAY) {
  2231.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2232.     if (pwent) {
  2233.         if (which == O_GPWNAM)
  2234.         str_numset(str, (double)pwent->pw_uid);
  2235.         else
  2236.         str_set(str, pwent->pw_name);
  2237.     }
  2238.     return sp;
  2239.     }
  2240.  
  2241.     if (pwent) {
  2242.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2243.     str_set(str, pwent->pw_name);
  2244.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2245.     str_set(str, pwent->pw_passwd);
  2246.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2247.     str_numset(str, (double)pwent->pw_uid);
  2248.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2249.     str_numset(str, (double)pwent->pw_gid);
  2250.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2251. #ifdef PWCHANGE
  2252.     str_numset(str, (double)pwent->pw_change);
  2253. #else
  2254. #ifdef PWQUOTA
  2255.     str_numset(str, (double)pwent->pw_quota);
  2256. #else
  2257. #ifdef PWAGE
  2258.     str_set(str, pwent->pw_age);
  2259. #endif
  2260. #endif
  2261. #endif
  2262.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2263. #ifdef PWCLASS
  2264.     str_set(str,pwent->pw_class);
  2265. #else
  2266. #ifdef PWCOMMENT
  2267.     str_set(str, pwent->pw_comment);
  2268. #endif
  2269. #endif
  2270.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2271.     str_set(str, pwent->pw_gecos);
  2272.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2273.     str_set(str, pwent->pw_dir);
  2274.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2275.     str_set(str, pwent->pw_shell);
  2276. #ifdef PWEXPIRE
  2277.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2278.     str_numset(str, (double)pwent->pw_expire);
  2279. #endif
  2280.     }
  2281.  
  2282.     return sp;
  2283. #else
  2284.     fatal("password routines not implemented");
  2285. #endif
  2286. }
  2287.  
  2288. int
  2289. do_ggrent(which,gimme,arglast)
  2290. int which;
  2291. int gimme;
  2292. int *arglast;
  2293. {
  2294. #ifdef I_GRP
  2295.     register ARRAY *ary = stack;
  2296.     register int sp = arglast[0];
  2297.     register char **elem;
  2298.     register STR *str;
  2299.     struct group *getgrnam();
  2300.     struct group *getgrgid();
  2301.     struct group *getgrent();
  2302.     struct group *grent;
  2303.  
  2304.     if (which == O_GGRNAM) {
  2305.     char *name = str_get(ary->ary_array[sp+1]);
  2306.  
  2307.     grent = getgrnam(name);
  2308.     }
  2309.     else if (which == O_GGRGID) {
  2310.     int gid = (int)str_gnum(ary->ary_array[sp+1]);
  2311.  
  2312.     grent = getgrgid(gid);
  2313.     }
  2314.     else
  2315.     grent = getgrent();
  2316.  
  2317.     if (gimme != G_ARRAY) {
  2318.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2319.     if (grent) {
  2320.         if (which == O_GGRNAM)
  2321.         str_numset(str, (double)grent->gr_gid);
  2322.         else
  2323.         str_set(str, grent->gr_name);
  2324.     }
  2325.     return sp;
  2326.     }
  2327.  
  2328.     if (grent) {
  2329.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2330.     str_set(str, grent->gr_name);
  2331.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2332.     str_set(str, grent->gr_passwd);
  2333.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2334.     str_numset(str, (double)grent->gr_gid);
  2335.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2336.     for (elem = grent->gr_mem; *elem; elem++) {
  2337.         str_cat(str, *elem);
  2338.         if (elem[1])
  2339.         str_ncat(str," ",1);
  2340.     }
  2341.     }
  2342.  
  2343.     return sp;
  2344. #else
  2345.     fatal("group routines not implemented");
  2346. #endif
  2347. }
  2348.  
  2349. int
  2350. do_dirop(optype,stab,gimme,arglast)
  2351. int optype;
  2352. STAB *stab;
  2353. int gimme;
  2354. int *arglast;
  2355. {
  2356. #if defined(DIRENT) && defined(HAS_READDIR)
  2357.     register ARRAY *ary = stack;
  2358.     register STR **st = ary->ary_array;
  2359.     register int sp = arglast[1];
  2360.     register STIO *stio;
  2361.     long along;
  2362. #ifndef apollo
  2363.     struct DIRENT *readdir();
  2364. #endif
  2365.     register struct DIRENT *dp;
  2366.  
  2367.     if (!stab)
  2368.     goto nope;
  2369.     if (!(stio = stab_io(stab)))
  2370.     stio = stab_io(stab) = stio_new();
  2371.     if (!stio->dirp && optype != O_OPEN_DIR)
  2372.     goto nope;
  2373.     st[sp] = &str_yes;
  2374.     switch (optype) {
  2375.     case O_OPEN_DIR:
  2376.     if (stio->dirp)
  2377.         closedir(stio->dirp);
  2378.     if (!(stio->dirp = opendir(str_get(st[sp+1]))))
  2379.         goto nope;
  2380.     break;
  2381.     case O_READDIR:
  2382.     if (gimme == G_ARRAY) {
  2383.         --sp;
  2384.         /*SUPPRESS 560*/
  2385.         while (dp = readdir(stio->dirp)) {
  2386. #ifdef DIRNAMLEN
  2387.         (void)astore(ary,++sp,
  2388.           str_2mortal(str_make(dp->d_name,dp->d_namlen)));
  2389. #else
  2390.         (void)astore(ary,++sp,
  2391.           str_2mortal(str_make(dp->d_name,0)));
  2392. #endif
  2393.         }
  2394.     }
  2395.     else {
  2396.         if (!(dp = readdir(stio->dirp)))
  2397.         goto nope;
  2398.         st[sp] = str_mortal(&str_undef);
  2399. #ifdef DIRNAMLEN
  2400.         str_nset(st[sp], dp->d_name, dp->d_namlen);
  2401. #else
  2402.         str_set(st[sp], dp->d_name);
  2403. #endif
  2404.     }
  2405.     break;
  2406. #if defined(HAS_TELLDIR) || defined(telldir)
  2407.     case O_TELLDIR: {
  2408. #ifndef telldir
  2409.         long telldir();
  2410. #endif
  2411.         st[sp] = str_mortal(&str_undef);
  2412.         str_numset(st[sp], (double)telldir(stio->dirp));
  2413.         break;
  2414.     }
  2415. #endif
  2416. #if defined(HAS_SEEKDIR) || defined(seekdir)
  2417.     case O_SEEKDIR:
  2418.     st[sp] = str_mortal(&str_undef);
  2419.     along = (long)str_gnum(st[sp+1]);
  2420.     (void)seekdir(stio->dirp,along);
  2421.     break;
  2422. #endif
  2423. #if defined(HAS_REWINDDIR) || defined(rewinddir)
  2424.     case O_REWINDDIR:
  2425.     st[sp] = str_mortal(&str_undef);
  2426.     (void)rewinddir(stio->dirp);
  2427.     break;
  2428. #endif
  2429.     case O_CLOSEDIR:
  2430.     st[sp] = str_mortal(&str_undef);
  2431.     (void)closedir(stio->dirp);
  2432.     stio->dirp = 0;
  2433.     break;
  2434.     default:
  2435.     goto phooey;
  2436.     }
  2437.     return sp;
  2438.  
  2439. nope:
  2440.     st[sp] = &str_undef;
  2441.     if (!errno)
  2442.     errno = EBADF;
  2443.     return sp;
  2444.  
  2445. #endif
  2446. phooey:
  2447.     fatal("Unimplemented directory operation");
  2448. }
  2449.  
  2450. int
  2451. apply(type,arglast)
  2452. int type;
  2453. int *arglast;
  2454. {
  2455.     register STR **st = stack->ary_array;
  2456.     register int sp = arglast[1];
  2457.     register int items = arglast[2] - sp;
  2458.     register int val;
  2459.     register int val2;
  2460.     register int tot = 0;
  2461.     char *s;
  2462.  
  2463. #ifdef TAINT
  2464.     for (st += ++sp; items--; st++)
  2465.     tainted |= (*st)->str_tainted;
  2466.     st = stack->ary_array;
  2467.     sp = arglast[1];
  2468.     items = arglast[2] - sp;
  2469. #endif
  2470.     switch (type) {
  2471.     case O_CHMOD:
  2472. #ifdef TAINT
  2473.     taintproper("Insecure dependency in chmod");
  2474. #endif
  2475.     if (--items > 0) {
  2476.         tot = items;
  2477.         val = (int)str_gnum(st[++sp]);
  2478.         while (items--) {
  2479.         if (chmod(str_get(st[++sp]),val))
  2480.             tot--;
  2481.         }
  2482.     }
  2483.     break;
  2484. #ifdef HAS_CHOWN
  2485.     case O_CHOWN:
  2486. #ifdef TAINT
  2487.     taintproper("Insecure dependency in chown");
  2488. #endif
  2489.     if (items > 2) {
  2490.         items -= 2;
  2491.         tot = items;
  2492.         val = (int)str_gnum(st[++sp]);
  2493.         val2 = (int)str_gnum(st[++sp]);
  2494.         while (items--) {
  2495.         if (chown(str_get(st[++sp]),val,val2))
  2496.             tot--;
  2497.         }
  2498.     }
  2499.     break;
  2500. #endif
  2501. #ifdef HAS_KILL
  2502.     case O_KILL:
  2503. #ifdef TAINT
  2504.     taintproper("Insecure dependency in kill");
  2505. #endif
  2506.     if (--items > 0) {
  2507.         tot = items;
  2508.         s = str_get(st[++sp]);
  2509.         if (isUPPER(*s)) {
  2510.         if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
  2511.             s += 3;
  2512.         if (!(val = whichsig(s)))
  2513.             fatal("Unrecognized signal name \"%s\"",s);
  2514.         }
  2515.         else
  2516.         val = (int)str_gnum(st[sp]);
  2517.         if (val < 0) {
  2518.         val = -val;
  2519.         while (items--) {
  2520.             int proc = (int)str_gnum(st[++sp]);
  2521. #ifdef HAS_KILLPG
  2522.             if (killpg(proc,val))    /* BSD */
  2523. #else
  2524.             if (kill(-proc,val))    /* SYSV */
  2525. #endif
  2526.             tot--;
  2527.         }
  2528.         }
  2529.         else {
  2530.         while (items--) {
  2531.             if (kill((int)(str_gnum(st[++sp])),val))
  2532.             tot--;
  2533.         }
  2534.         }
  2535.     }
  2536.     break;
  2537. #endif
  2538.     case O_UNLINK:
  2539. #ifdef TAINT
  2540.     taintproper("Insecure dependency in unlink");
  2541. #endif
  2542.     tot = items;
  2543.     while (items--) {
  2544.         s = str_get(st[++sp]);
  2545.         if (euid || unsafe) {
  2546.         if (UNLINK(s))
  2547.             tot--;
  2548.         }
  2549.         else {    /* don't let root wipe out directories without -U */
  2550. #ifdef HAS_LSTAT
  2551.         if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2552. #else
  2553.         if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2554. #endif
  2555.             tot--;
  2556.         else {
  2557.             if (UNLINK(s))
  2558.             tot--;
  2559.         }
  2560.         }
  2561.     }
  2562.     break;
  2563.     case O_UTIME:
  2564. #ifdef TAINT
  2565.     taintproper("Insecure dependency in utime");
  2566. #endif
  2567.     if (items > 2) {
  2568. #ifdef I_UTIME
  2569.         struct utimbuf utbuf;
  2570. #else
  2571.         struct {
  2572.         long    actime;
  2573.         long    modtime;
  2574.         } utbuf;
  2575. #endif
  2576.  
  2577.         Zero(&utbuf, sizeof utbuf, char);
  2578.         utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
  2579.         utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
  2580.         items -= 2;
  2581. #ifndef lint
  2582.         tot = items;
  2583.         while (items--) {
  2584.         if (utime(str_get(st[++sp]),&utbuf))
  2585.             tot--;
  2586.         }
  2587. #endif
  2588.     }
  2589.     else
  2590.         items = 0;
  2591.     break;
  2592.     }
  2593.     return tot;
  2594. }
  2595.  
  2596. /* Do the permissions allow some operation?  Assumes statcache already set. */
  2597.  
  2598. int
  2599. cando(bit, effective, statbufp)
  2600. int bit;
  2601. int effective;
  2602. register struct stat *statbufp;
  2603. {
  2604. #ifdef DOSISH
  2605.     /* [Comments and code from Len Reed]
  2606.      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
  2607.      * to write-protected files.  The execute permission bit is set
  2608.      * by the Miscrosoft C library stat() function for the following:
  2609.      *        .exe files
  2610.      *        .com files
  2611.      *        .bat files
  2612.      *        directories
  2613.      * All files and directories are readable.
  2614.      * Directories and special files, e.g. "CON", cannot be
  2615.      * write-protected.
  2616.      * [Comment by Tom Dinger -- a directory can have the write-protect
  2617.      *        bit set in the file system, but DOS permits changes to
  2618.      *        the directory anyway.  In addition, all bets are off
  2619.      *        here for networked software, such as Novell and
  2620.      *        Sun's PC-NFS.]
  2621.      */
  2622.  
  2623.      /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
  2624.       * too so it will actually look into the files for magic numbers
  2625.       */
  2626.      return (bit & statbufp->st_mode) ? TRUE : FALSE;
  2627.  
  2628. #else /* ! MSDOS */
  2629.     if ((effective ? euid : uid) == 0) {    /* root is special */
  2630.     if (bit == S_IXUSR) {
  2631.         if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
  2632.         return TRUE;
  2633.     }
  2634.     else
  2635.         return TRUE;        /* root reads and writes anything */
  2636.     return FALSE;
  2637.     }
  2638.     if (statbufp->st_uid == (effective ? euid : uid) ) {
  2639.     if (statbufp->st_mode & bit)
  2640.         return TRUE;    /* ok as "user" */
  2641.     }
  2642.     else if (ingroup((int)statbufp->st_gid,effective)) {
  2643.     if (statbufp->st_mode & bit >> 3)
  2644.         return TRUE;    /* ok as "group" */
  2645.     }
  2646.     else if (statbufp->st_mode & bit >> 6)
  2647.     return TRUE;    /* ok as "other" */
  2648.     return FALSE;
  2649. #endif /* ! MSDOS */
  2650. }
  2651.  
  2652. int
  2653. ingroup(testgid,effective)
  2654. int testgid;
  2655. int effective;
  2656. {
  2657.     if (testgid == (effective ? egid : gid))
  2658.     return TRUE;
  2659. #ifdef HAS_GETGROUPS
  2660. #ifndef NGROUPS
  2661. #define NGROUPS 32
  2662. #endif
  2663.     {
  2664.     GROUPSTYPE gary[NGROUPS];
  2665.     int anum;
  2666.  
  2667.     anum = getgroups(NGROUPS,gary);
  2668.     while (--anum >= 0)
  2669.         if (gary[anum] == testgid)
  2670.         return TRUE;
  2671.     }
  2672. #endif
  2673.     return FALSE;
  2674. }
  2675.  
  2676. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  2677.  
  2678. int
  2679. do_ipcget(optype, arglast)
  2680. int optype;
  2681. int *arglast;
  2682. {
  2683.     register STR **st = stack->ary_array;
  2684.     register int sp = arglast[0];
  2685.     key_t key;
  2686.     int n, flags;
  2687.  
  2688.     key = (key_t)str_gnum(st[++sp]);
  2689.     n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
  2690.     flags = (int)str_gnum(st[++sp]);
  2691.     errno = 0;
  2692.     switch (optype)
  2693.     {
  2694. #ifdef HAS_MSG
  2695.     case O_MSGGET:
  2696.     return msgget(key, flags);
  2697. #endif
  2698. #ifdef HAS_SEM
  2699.     case O_SEMGET:
  2700.     return semget(key, n, flags);
  2701. #endif
  2702. #ifdef HAS_SHM
  2703.     case O_SHMGET:
  2704.     return shmget(key, n, flags);
  2705. #endif
  2706. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2707.     default:
  2708.     fatal("%s not implemented", opname[optype]);
  2709. #endif
  2710.     }
  2711.     return -1;            /* should never happen */
  2712. }
  2713.  
  2714. int
  2715. do_ipcctl(optype, arglast)
  2716. int optype;
  2717. int *arglast;
  2718. {
  2719.     register STR **st = stack->ary_array;
  2720.     register int sp = arglast[0];
  2721.     STR *astr;
  2722.     char *a;
  2723.     int id, n, cmd, infosize, getinfo, ret;
  2724.  
  2725.     id = (int)str_gnum(st[++sp]);
  2726.     n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
  2727.     cmd = (int)str_gnum(st[++sp]);
  2728.     astr = st[++sp];
  2729.  
  2730.     infosize = 0;
  2731.     getinfo = (cmd == IPC_STAT);
  2732.  
  2733.     switch (optype)
  2734.     {
  2735. #ifdef HAS_MSG
  2736.     case O_MSGCTL:
  2737.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2738.         infosize = sizeof(struct msqid_ds);
  2739.     break;
  2740. #endif
  2741. #ifdef HAS_SHM
  2742.     case O_SHMCTL:
  2743.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2744.         infosize = sizeof(struct shmid_ds);
  2745.     break;
  2746. #endif
  2747. #ifdef HAS_SEM
  2748.     case O_SEMCTL:
  2749.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2750.         infosize = sizeof(struct semid_ds);
  2751.     else if (cmd == GETALL || cmd == SETALL)
  2752.     {
  2753.         struct semid_ds semds;
  2754.         if (semctl(id, 0, IPC_STAT, &semds) == -1)
  2755.         return -1;
  2756.         getinfo = (cmd == GETALL);
  2757.         infosize = semds.sem_nsems * sizeof(short);
  2758.         /* "short" is technically wrong but much more portable
  2759.            than guessing about u_?short(_t)? */
  2760.     }
  2761.     break;
  2762. #endif
  2763. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2764.     default:
  2765.     fatal("%s not implemented", opname[optype]);
  2766. #endif
  2767.     }
  2768.  
  2769.     if (infosize)
  2770.     {
  2771.     if (getinfo)
  2772.     {
  2773.         STR_GROW(astr, infosize+1);
  2774.         a = str_get(astr);
  2775.     }
  2776.     else
  2777.     {
  2778.         a = str_get(astr);
  2779.         if (astr->str_cur != infosize)
  2780.         {
  2781.         errno = EINVAL;
  2782.         return -1;
  2783.         }
  2784.     }
  2785.     }
  2786.     else
  2787.     {
  2788.     int i = (int)str_gnum(astr);
  2789.     a = (char *)i;        /* ouch */
  2790.     }
  2791.     errno = 0;
  2792.     switch (optype)
  2793.     {
  2794. #ifdef HAS_MSG
  2795.     case O_MSGCTL:
  2796.     ret = msgctl(id, cmd, (struct msqid_ds *)a);
  2797.     break;
  2798. #endif
  2799. #ifdef HAS_SEM
  2800.     case O_SEMCTL:
  2801.     ret = semctl(id, n, cmd, a);
  2802.     break;
  2803. #endif
  2804. #ifdef HAS_SHM
  2805.     case O_SHMCTL:
  2806.     ret = shmctl(id, cmd, (struct shmid_ds *)a);
  2807.     break;
  2808. #endif
  2809.     }
  2810.     if (getinfo && ret >= 0) {
  2811.     astr->str_cur = infosize;
  2812.     astr->str_ptr[infosize] = '\0';
  2813.     }
  2814.     return ret;
  2815. }
  2816.  
  2817. int
  2818. do_msgsnd(arglast)
  2819. int *arglast;
  2820. {
  2821. #ifdef HAS_MSG
  2822.     register STR **st = stack->ary_array;
  2823.     register int sp = arglast[0];
  2824.     STR *mstr;
  2825.     char *mbuf;
  2826.     int id, msize, flags;
  2827.  
  2828.     id = (int)str_gnum(st[++sp]);
  2829.     mstr = st[++sp];
  2830.     flags = (int)str_gnum(st[++sp]);
  2831.     mbuf = str_get(mstr);
  2832.     if ((msize = mstr->str_cur - sizeof(long)) < 0) {
  2833.     errno = EINVAL;
  2834.     return -1;
  2835.     }
  2836.     errno = 0;
  2837.     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
  2838. #else
  2839.     fatal("msgsnd not implemented");
  2840. #endif
  2841. }
  2842.  
  2843. int
  2844. do_msgrcv(arglast)
  2845. int *arglast;
  2846. {
  2847. #ifdef HAS_MSG
  2848.     register STR **st = stack->ary_array;
  2849.     register int sp = arglast[0];
  2850.     STR *mstr;
  2851.     char *mbuf;
  2852.     long mtype;
  2853.     int id, msize, flags, ret;
  2854.  
  2855.     id = (int)str_gnum(st[++sp]);
  2856.     mstr = st[++sp];
  2857.     msize = (int)str_gnum(st[++sp]);
  2858.     mtype = (long)str_gnum(st[++sp]);
  2859.     flags = (int)str_gnum(st[++sp]);
  2860.     mbuf = str_get(mstr);
  2861.     if (mstr->str_cur < sizeof(long)+msize+1) {
  2862.     STR_GROW(mstr, sizeof(long)+msize+1);
  2863.     mbuf = str_get(mstr);
  2864.     }
  2865.     errno = 0;
  2866.     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
  2867.     if (ret >= 0) {
  2868.     mstr->str_cur = sizeof(long)+ret;
  2869.     mstr->str_ptr[sizeof(long)+ret] = '\0';
  2870.     }
  2871.     return ret;
  2872. #else
  2873.     fatal("msgrcv not implemented");
  2874. #endif
  2875. }
  2876.  
  2877. int
  2878. do_semop(arglast)
  2879. int *arglast;
  2880. {
  2881. #ifdef HAS_SEM
  2882.     register STR **st = stack->ary_array;
  2883.     register int sp = arglast[0];
  2884.     STR *opstr;
  2885.     char *opbuf;
  2886.     int id, opsize;
  2887.  
  2888.     id = (int)str_gnum(st[++sp]);
  2889.     opstr = st[++sp];
  2890.     opbuf = str_get(opstr);
  2891.     opsize = opstr->str_cur;
  2892.     if (opsize < sizeof(struct sembuf)
  2893.     || (opsize % sizeof(struct sembuf)) != 0) {
  2894.     errno = EINVAL;
  2895.     return -1;
  2896.     }
  2897.     errno = 0;
  2898.     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
  2899. #else
  2900.     fatal("semop not implemented");
  2901. #endif
  2902. }
  2903.  
  2904. int
  2905. do_shmio(optype, arglast)
  2906. int optype;
  2907. int *arglast;
  2908. {
  2909. #ifdef HAS_SHM
  2910.     register STR **st = stack->ary_array;
  2911.     register int sp = arglast[0];
  2912.     STR *mstr;
  2913.     char *mbuf, *shm;
  2914.     int id, mpos, msize;
  2915.     struct shmid_ds shmds;
  2916. #ifndef VOIDSHMAT
  2917.     extern char *shmat();
  2918. #endif
  2919.  
  2920.     id = (int)str_gnum(st[++sp]);
  2921.     mstr = st[++sp];
  2922.     mpos = (int)str_gnum(st[++sp]);
  2923.     msize = (int)str_gnum(st[++sp]);
  2924.     errno = 0;
  2925.     if (shmctl(id, IPC_STAT, &shmds) == -1)
  2926.     return -1;
  2927.     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
  2928.     errno = EFAULT;        /* can't do as caller requested */
  2929.     return -1;
  2930.     }
  2931.     shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
  2932.     if (shm == (char *)-1)    /* I hate System V IPC, I really do */
  2933.     return -1;
  2934.     mbuf = str_get(mstr);
  2935.     if (optype == O_SHMREAD) {
  2936.     if (mstr->str_cur < msize) {
  2937.         STR_GROW(mstr, msize+1);
  2938.         mbuf = str_get(mstr);
  2939.     }
  2940.     Copy(shm + mpos, mbuf, msize, char);
  2941.     mstr->str_cur = msize;
  2942.     mstr->str_ptr[msize] = '\0';
  2943.     }
  2944.     else {
  2945.     int n;
  2946.  
  2947.     if ((n = mstr->str_cur) > msize)
  2948.         n = msize;
  2949.     Copy(mbuf, shm + mpos, n, char);
  2950.     if (n < msize)
  2951.         memzero(shm + mpos + n, msize - n);
  2952.     }
  2953.     return shmdt(shm);
  2954. #else
  2955.     fatal("shm I/O not implemented");
  2956. #endif
  2957. }
  2958.  
  2959. #endif /* SYSV IPC */
  2960.